home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 1 / Atari Mega Archive - Volume 1.iso / telecomm / sticpsrc.lzh / SOURCE.ARC / NRS.C < prev    next >
C/C++ Source or Header  |  1989-07-25  |  8KB  |  331 lines

  1. /* This module implements the serial line framing method used by
  2.  * net/rom nodes.  This allows the net/rom software to talk to
  3.  * an actual net/rom over its serial interface, which is useful
  4.  * if we want to do packet switching for multi-line wormholes.
  5.  * Dan Frank, W9NK
  6.  */
  7. #include <stdio.h>
  8. #include "global.h"
  9. #include "mbuf.h"
  10. #include "iface.h"
  11. #include "ax25.h"
  12. #include "nrs.h"
  13. #include "asy.h"
  14. #include "combios.h"
  15. #include "trace.h"
  16.  
  17. /* control structures, sort of overlayed on async control blocks */
  18. struct nrs nrs[ASY_MAX];
  19.  
  20. /* Send a raw net/rom serial frame */
  21. nrs_raw(interface,bp)
  22. struct interface *interface;
  23. struct mbuf *bp;
  24. {
  25.     dump(interface,IF_TRACE_OUT,TRACE_AX25,bp);
  26.  
  27.     /* Queue a frame on the output queue and start transmitter */
  28.     nrsq(interface->dev,bp);
  29. }
  30.  
  31. /* Encode a raw packet in net/rom framing, put on link output queue, and kick
  32.  * transmitter
  33.  */
  34. static
  35. nrsq(dev,bp)
  36. int16 dev;        /* Serial line number */
  37. struct mbuf *bp;    /* Buffer to be sent */
  38. {
  39.     register struct nrs *sp;
  40.     struct mbuf *nrs_encode();
  41.  
  42.     if((bp = nrs_encode(bp)) == NULLBUF)
  43.         return;
  44.  
  45.     sp = &nrs[dev];
  46.     enqueue(&sp->sndq,bp);
  47.     sp->sndcnt++;
  48.     if(sp->tbp == NULLBUF)
  49.         nrasy_start(dev);
  50. }
  51.  
  52. /* Start output, if possible, on asynch device dev */
  53. static
  54. nrasy_start(dev)
  55. int16 dev;
  56. {
  57.     register struct nrs *sp;
  58.     int asy_output();
  59. #ifdef    COMBIOS
  60.     struct com *cp;
  61.     unsigned char c;
  62.     unsigned stat;
  63.     int numsend;
  64. #endif
  65.  
  66. #ifdef    COMBIOS
  67.     com[dev].stat |= (stat = combios(0x0300,dev));
  68.     if(!(stat & 0x2000))
  69. #else
  70.     if(!stxrdy(dev))
  71. #endif
  72.         return;        /* Transmitter not ready */
  73.  
  74.     sp = &nrs[dev];
  75.  
  76.     if(sp->tbp != NULLBUF){
  77. #ifdef    COMBIOS
  78.         goto comsend;    /* still something to send */
  79. #else
  80.         /* transmission just completed */
  81.         free_p(sp->tbp);
  82.         sp->tbp = NULLBUF;
  83. #endif
  84.     }
  85.  
  86.     if(sp->sndq == NULLBUF)
  87.         return; /* No work */
  88.  
  89.     sp->tbp = dequeue(&sp->sndq);
  90.     sp->sndcnt--;
  91.  
  92. #ifdef    COMBIOS
  93. comsend:
  94.     cp = &com[dev];                /* quick ptr to our com */
  95.  
  96.     if ((numsend = cp->txbuf) == 0)
  97.         numsend = cp->speed;        /* enough for 10 seconds */
  98.  
  99.     while(--numsend && pullup(&sp->tbp,&c,1) == 1) {
  100.         cp->stat |= (stat = combios(0x0100 | c,dev)) & 0x7f00;
  101.         if (cp->txbuf == 0 &&        /* no explicit tx buffer max */
  102.             (stat & 0xa000) != 0x2000)    /* timeout or full */
  103.             break;
  104.     }
  105. #else
  106.     asy_output(dev,sp->tbp->data,sp->tbp->cnt);
  107. #endif
  108. }
  109.  
  110. /* Encode a packet in net/rom serial format */
  111. static
  112. struct mbuf *
  113. nrs_encode(bp)
  114. struct mbuf *bp;
  115. {
  116.     struct mbuf *lbp;    /* Mbuf containing line-ready packet */
  117.     register char *cp;
  118.     char c;
  119.     unsigned char csum = 0;
  120.  
  121.     /* Allocate output mbuf that's twice as long as the packet.
  122.      * This is a worst-case guess (consider a packet full of STX's!)
  123.      * Add five bytes for STX, ETX, checksum, and two nulls.
  124.      */
  125.     lbp = alloc_mbuf(2*len_mbuf(bp) + 5);
  126.     if(lbp == NULLBUF){
  127.         /* No space; drop */
  128.         free_p(bp);
  129.         return NULLBUF;
  130.     }
  131.     cp = lbp->data;
  132.  
  133.     *cp++ = STX;
  134.  
  135.     /* Copy input to output, escaping special characters */
  136.     while(pullup(&bp,&c,1) == 1){
  137.         switch(uchar(c)){
  138.         case STX:
  139.         case ETX:
  140.         case DLE:
  141.             *cp++ = DLE;
  142.             /* notice drop through to default */
  143.         default:
  144.             *cp++ = c;
  145.         }
  146.         csum += uchar(c);
  147.     }
  148.     *cp++ = ETX;
  149.     *cp++ = csum;
  150.     *cp++ = NUL;
  151.     *cp++ = NUL;
  152.  
  153.     lbp->cnt = cp - lbp->data;
  154.     return lbp;
  155. }
  156. /* Process incoming bytes in net/rom serial format
  157.  * When a buffer is complete, return it; otherwise NULLBUF
  158.  */
  159. static
  160. struct mbuf *
  161. nrs_decode(dev,c)
  162. int16 dev;    /* net/rom unit number */
  163. char c;        /* Incoming character */
  164. {
  165.     struct mbuf *bp;
  166.     register struct nrs *sp;
  167.  
  168.     sp = &nrs[dev];
  169.     switch(sp->state) {
  170.         case NRS_INTER:
  171.             if (uchar(c) == STX) {    /* look for start of frame */
  172.                 sp->state = NRS_INPACK; /* we're in a packet */
  173.                 sp->csum = 0;        /* reset checksum */
  174. #ifdef    COMBIOS
  175.                 com[dev].stat = 0;    /* reset error bits */
  176. #endif
  177.             }
  178.             return NULLBUF;
  179.  
  180.         case NRS_CSUM:
  181.             bp = sp->rbp;
  182.             sp->rbp = NULLBUF;
  183.             sp->rcnt = 0;
  184.             sp->state = NRS_INTER;    /* go back to inter-packet state */
  185.             if (sp->csum == uchar(c)    /* checksum ok */
  186. #ifdef    COMBIOS
  187.                 && !(com[dev].stat & 0x1a00) /* no overruns etc */
  188. #endif
  189.                ) {
  190.                 sp->packets++;
  191.                 return bp;
  192.             }
  193.             free_p(bp);        /* drop packet with bad checksum */
  194.             sp->errors++;        /* increment error count */
  195.             return NULLBUF;
  196.  
  197.         case NRS_ESCAPE:
  198.             sp->state = NRS_INPACK; /* end of escape */
  199.             break;            /* this will drop through to char processing */
  200.  
  201.         case NRS_INPACK:
  202.             switch (uchar(c)) {
  203.                 /* If we see an STX in a packet, assume that previous */
  204.                 /* packet was trashed, and start a new packet */
  205.                 case STX:
  206.                     free_p(sp->rbp);
  207.                     sp->rbp = NULLBUF;
  208.                     sp->rcnt = 0;
  209.                     sp->csum = 0;
  210. #ifdef    COMBIOS
  211.                     com[dev].stat = 0;
  212. #endif
  213.                     sp->errors++;
  214.                     return NULLBUF;
  215.  
  216.                 case ETX:
  217.                     sp->state = NRS_CSUM;  /* look for checksum */
  218.                     return NULLBUF;
  219.  
  220.                 case DLE:
  221.                     sp->state = NRS_ESCAPE;
  222.                     return NULLBUF;
  223.             }
  224.     }
  225. #ifdef    COMBIOS
  226.     if (com[dev].stat & 0x1a00)        /* recv error detected? */
  227.         return NULLBUF;            /* don't waste buffers */
  228. #endif
  229.  
  230.     /* If we get to here, it's with a character that's part of the packet.
  231.      * Make sure there's space for it.
  232.      */
  233.     if(sp->rbp == NULLBUF){
  234.         /* Allocate first mbuf for new packet */
  235.         if((sp->rbp1 = sp->rbp = alloc_mbuf(NRS_ALLOC)) == NULLBUF) {
  236.             sp->state = NRS_INTER;
  237.             return NULLBUF; /* No memory, drop */
  238.         }
  239.         sp->rcp = sp->rbp->data;
  240.     } else if(sp->rbp1->cnt == NRS_ALLOC){
  241.         /* Current mbuf is full; link in another */
  242.         if((sp->rbp1->next = alloc_mbuf(NRS_ALLOC)) == NULLBUF){
  243.             /* No memory, drop whole thing */
  244.             free_p(sp->rbp);
  245.             sp->rbp = NULLBUF;
  246.             sp->rcnt = 0;
  247.             sp->state = NRS_INTER;
  248.             return NULLBUF;
  249.         }
  250.         sp->rbp1 = sp->rbp1->next;
  251.         sp->rcp = sp->rbp1->data;
  252.     }
  253.     /* Store the character, increment fragment and total
  254.      * byte counts
  255.      */
  256.     *sp->rcp++ = c;
  257.     sp->rbp1->cnt++;
  258.     sp->rcnt++;
  259.     sp->csum += uchar(c);  /* add to checksum */
  260.     return NULLBUF;
  261. }
  262.  
  263. /* Process net/rom serial line I/O */
  264. void
  265. nrs_recv(interface)
  266. struct interface *interface;
  267. {
  268. #ifdef    COMBIOS
  269.     register unsigned stat;
  270. #else
  271.     char c;
  272. #endif
  273.     struct mbuf *bp;
  274.     int16 dev;
  275.     int16 asy_recv(),com_recv();
  276.     int ax_recv();
  277.  
  278.     dev = interface->dev;
  279.  
  280. #ifdef    COMBIOS
  281.     /* Process any pending input */
  282. fossil:
  283.     com[dev].stat |= (stat = combios(0x0300,dev));
  284.  
  285.     while(stat & 0x0100) {
  286.         com[dev].stat |= (stat = combios(0x0200,dev));
  287.  
  288.         if((bp = nrs_decode(dev,stat & 0xff)) != NULLBUF) {
  289.             dump(interface,IF_TRACE_IN,TRACE_AX25,bp);
  290.             ax_recv(interface,bp);
  291.         }
  292.  
  293.         if(com[dev].drtype == 3)
  294.             goto fossil;        /* FOSSIL needs new status */
  295.     }
  296.  
  297.     /* Kick the transmitter if it's idle */
  298.     if(stat & 0x2000)
  299.         nrasy_start(dev);
  300. #else
  301.     /* Process any pending input */
  302.     while(asy_recv(dev,&c,1) != 0)
  303.         if((bp = nrs_decode(dev,c)) != NULLBUF) {
  304.             dump(interface,IF_TRACE_IN,TRACE_AX25,bp);
  305.             ax_recv(interface,bp);
  306.         }
  307.  
  308.     /* Kick the transmitter if it's idle */
  309.     nrasy_start(dev);
  310. #endif
  311. }
  312.  
  313. /* donrstat:  display status of active net/rom serial interfaces */
  314. donrstat(argc,argv)
  315. int argc;
  316. char *argv[];
  317. {
  318.     register struct nrs *np;
  319.     register int i;
  320.  
  321.     printf("Interface  SndQ  RcvB  NumReceived  CSumErrors\n");
  322.  
  323.     for (i = 0, np = nrs; i < ASY_MAX; i++, np++)
  324.         if (np->iface != NULLIF)
  325.             printf(" %8s   %3d  %4d   %10lu  %10lu\n",
  326.                     np->iface->name, np->sndcnt, np->rcnt,
  327.                     np->packets, np->errors);
  328.  
  329.     return 0;
  330. }
  331.